﻿using System;
using System.Linq;
using System.Reflection;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    ///  Activator类型扩展方法类
    /// </summary>
    public static class ActivatorEx
    {
        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="typeFullName">类型名称[格式:类型名,程序集命名.例如:Oracle.ManagedDataAccess.Client.OracleConnection,Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342]</param>
        /// <param name="args">构造函数参数</param>
        public static object CreateInstance(string typeFullName, params object[] args)
        {
            if (string.IsNullOrWhiteSpace(typeFullName))
            {
                return null;
            }

            Type type = TypeEx.GetType(typeFullName);
            if (type == null)
            {
                return null;
            }

            return Activator.CreateInstance(type, args);
        }

        /// <summary>
        /// 创建指定接口类型实例 
        /// </summary>
        /// <typeparam name="T">接口类型</typeparam>
        /// <param name="type">实现该接口的类</param>
        /// <param name="args">构造函数个数数组</param>
        /// <returns>接口实例</returns>
        public static T CreateInstance<T>(Type type, params object[] args)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            Type targetType = typeof(T);
            if (targetType != type &&
                type.GetInterface(targetType.FullName) == null &&
                !type.IsSubclassOf(targetType))
            {
                throw new ArgumentException($"类型{type.FullName}未继承{targetType.FullName}");
            }

            return (T)CreateInstance(type, args);
        }

        /// <summary>
        /// 创建指定接口类型实例 
        /// </summary>
        /// <param name="type">实现该接口的类</param>
        /// <param name="args">构造函数个数数组</param>
        /// <returns>接口实例</returns>
        public static object CreateInstance(Type type, params object[] args)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (type.IsAbstract)
            {
                throw new ArgumentException($"类型{type.FullName}是抽象类,不允许创建实例.");
            }

            ConstructorInfo[] constructors = type.GetConstructors();
            if (args != null && args.Length > 0)
            {
                bool interuptFlag;
                foreach (ConstructorInfo constructor in constructors)
                {
                    ParameterInfo[] parameterInfos = constructor.GetParameters();
                    if (parameterInfos == null || parameterInfos.Length != args.Length)
                    {
                        continue;
                    }

                    interuptFlag = false;
                    for (int i = 0; i < args.Length; i++)
                    {
                        if (args[i] == null)
                        {
                            if (parameterInfos[i].ParameterType.IsClass || Nullable.GetUnderlyingType(parameterInfos[i].ParameterType) != null)
                            {
                                //参数为null,但构造函数对应参数允许为null
                                continue;
                            }
                            else
                            {
                                //参数为null,但构造函数对应参数不允许为null,中断循环
                                interuptFlag = true;
                                break;
                            }
                        }
                        else
                        {
                            Type argsType = args[i].GetType();
                            if (argsType != parameterInfos[i].ParameterType &&
                                !argsType.IsSubclassOf(parameterInfos[i].ParameterType) &&
                                argsType != Nullable.GetUnderlyingType(parameterInfos[i].ParameterType))
                            {
                                //参数不为null,参数类型与构造函数对应参数不匹配,中断循环
                                interuptFlag = true;
                                break;
                            }
                        }
                    }

                    if (interuptFlag)
                    {
                        continue;
                    }
                    else
                    {
                        return Activator.CreateInstance(type, args);
                    }
                }

                throw new ArgumentException($"类型{type.FullName}没有与形参匹配的构造函数,创建实例失败");
            }
            else
            {
                if (!constructors.Any(t => { return t.GetParameters().Length == 0; }))
                {
                    throw new ArgumentException($"类型{type.FullName}没有无参构造函数,创建实例失败");
                }

                return Activator.CreateInstance(type);
            }
        }
    }
}
